﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using IndicoRender;
using IndicoInterface.SimpleAgendaDataModel;
using System.ComponentModel.Composition;
using RenderEngineInterfaces;
using System.Threading.Tasks;
using DeepZoomPivotConstructor.VisualLib;
using System.Drawing;
using RenderEngine;
using DeepZoomPivotConstructor.VisualLib.Hotspots;

namespace t_IndicoRender
{
    /// <summary>
    /// Test the rendering of sessions
    /// </summary>
    [TestClass]
    public class t_RenderIndicoSession
    {
        public t_RenderIndicoSession()
        {
        }

        [TestInitialize]
        public void InitForTest()
        {
            t_TestingLibrary.Utilities.MyClassInit();
            t_TestingLibrary.Utilities.AddPart(new RenderControl());
            t_TestingLibrary.Utilities.AddPart(new LayoutHelper());
        }

        [TestCleanup]
        public void ShutDownTest()
        {
            t_TestingLibrary.Utilities.MyClassDone();
        }

        [Import]
        private IRenderEngine MyRender { get; set; }

        [TestMethod]
        public void TestCreate()
        {
            RenderIndicoSession s = new RenderIndicoSession();
        }

        [TestMethod]
        public void TestCanRender()
        {
            RenderIndicoSession s = new RenderIndicoSession();
            Session ses = new Session()
            {
                Title = "Session Title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now
            };
            Assert.AreEqual(RenderPluginPriority.RPPGeneric, s.RenderPriority(ses), "Wrong priority comes back for a basic render!");
        }

        [TestMethod]
        public void TestNullRender()
        {
            RenderIndicoSession s = new RenderIndicoSession();
            t_TestingLibrary.Utilities.Compose(s);

            var result = s.Render((Session) null);
            Assert.IsNotNull(result, "Should  not be null");
            Assert.IsNull(result.Result, "Actual value should be null");
        }

        [TestMethod]
        public void TestRenderEmptySession()
        {
            RenderIndicoSession s = new RenderIndicoSession();
            t_TestingLibrary.Utilities.Compose(s);

            Session ses = new Session()
            {
                Title = "Session Title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now
            };

            var result = s.Render(ses);
            Assert.IsNotNull(result, "Should  not be null");
            Assert.IsNull(result.Result, "Actual value should be null");
        }

        [Export(typeof(IRenderItem))]
        [RenderInfo(typeof(Talk))]
        class RenderTalkAsSingleVisual : IRenderItem
        {
            public double XWidth = 1.0;
            public double XHeight = 2.0;

            public Task<Visual>  Render(object what)
            {
                return Task<Visual>.Factory.StartNew(() =>
                    {
                        Talk t = what as Talk;
                        var bt = new VisualBitmapImage(XWidth, XHeight, 100, Color.Black);
                        bt.Info = new Visual.VisualInfo()
                        {
                            Title = t.Title,
                            Info = new string[] {"Some time later"}
                        };
                        return bt;
                    });
            }

            public RenderPluginPriority  RenderPriority(object what)
            {
                return RenderPluginPriority.RPPGeneric;
            }
        }

        [TestMethod]
        public void TestRender1Talk()
        {
            t_TestingLibrary.Utilities.AddPart(new RenderTalkAsSingleVisual());
            RenderIndicoSession s = new RenderIndicoSession();
            t_TestingLibrary.Utilities.Compose(s);

            Session ses = new Session()
            {
                Title = "Session Title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now
            };
            ses.Talks = CreateTalks(1);

            var result = s.Render(ses);
            Assert.IsNotNull(result, "Rendering session should give us something!");

            var vis = result.Result;
            Assert.IsNotNull(vis, "We should have gotten some visuals out of that!");

            Assert.AreEqual(2, vis.SGNodeList.Count, "Expected a talk image and a background image!");
            Assert.IsTrue(vis.Width < 11.0, "The session size is too big!");

            Assert.IsNotNull(vis.Info, "Expected real metadata for this session!");
            Assert.AreEqual("Session Title", vis.Info.Title, "Expected the title to be set correctly");
            Assert.IsNotNull(vis.Info.Info, "Expecting some string messages!");
            Assert.AreEqual(1, vis.Info.Info.Length, "Expected one extra message on session duration!");
        }

        [TestMethod]
        public void TestRenderOnlyMaterial()
        {
            t_TestingLibrary.Utilities.AddPart(new RenderTalkAsSingleVisual());
            RenderIndicoSession s = new RenderIndicoSession();
            t_TestingLibrary.Utilities.Compose(s);

            Session ses = new Session()
            {
                Title = "Session Title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now
            };
            ses.SessionMaterial = CreateTalks(1);

            var result = s.Render(ses);
            Assert.IsNotNull(result, "Rendering shoudl have given us something!");
            var v = result.Result;
            Assert.IsNotNull(v, "Rendering should have given us a visual!");

            Assert.AreEqual(2, v.SGNodeList.Count, "Expected a talk image and a background image!");
        }

        [TestMethod]
        public void TestRenderNullMaterialAndTalk()
        {
            Session ses = new Session()
            {
                Title = "Session Title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now
            };
            ses.SessionMaterial = new Talk[0];
            ses.Talks = new Talk[0];
        }

        /// <summary>
        /// Create a few talks for testing
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        private Talk[] CreateTalks(int n)
        {
            List<Talk> tlist = new List<Talk>();
            for (int i = 0; i < n; i++)
            {
                Talk t = new Talk()
                {
                    Title = "Talk # " + i.ToString(),
                    StartDate = DateTime.Now,
                    EndDate = DateTime.Now,
                    ID = (10 + i).ToString(),
                    Speakers = new string[] {"George"},
                    SlideURL = "http://www.nytimes.com"
                };
                tlist.Add(t);
            }
            return tlist.ToArray();
        }

        [TestMethod]
        public void TestRender10Talks()
        {
            RenderTalkAsSingleVisual rtalk = new RenderTalkAsSingleVisual();
            rtalk.XHeight = 20.0;
            rtalk.XWidth = 10.0;
            t_TestingLibrary.Utilities.AddPart(rtalk);
            RenderIndicoSession s = new RenderIndicoSession();
            t_TestingLibrary.Utilities.Compose(s);

            Session ses = new Session()
            {
                Title = "Session Title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now
            };
            ses.Talks = CreateTalks(10);

            var result = s.Render(ses);
            Assert.IsNotNull(result, "Rendering session should give us something!");

            var vis = result.Result;
            Assert.IsNotNull(vis, "We should have gotten some visuals out of that!");

            Assert.AreEqual(20, vis.SGNodeList.Count, "Expected a talk image and a background image!");
            Assert.IsTrue(vis.Width < 11.0, "The session size is too big!");
        }

        [TestMethod]
        public void TestRenderSessionWithTalkWithOnlySUbTalks()
        {
            RenderTalkAsSingleVisual rtalk = new RenderTalkAsSingleVisual();
            rtalk.XHeight = 20.0;
            rtalk.XWidth = 10.0;
            t_TestingLibrary.Utilities.AddPart(rtalk);
            RenderIndicoSession s = new RenderIndicoSession();
            t_TestingLibrary.Utilities.Compose(s);

            Session ses = new Session()
            {
                Title = "Session Title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now
            };

            ses.Talks = CreateTalks(1);
            ses.Talks[0].SubTalks = CreateTalks(2);
            ses.Talks[0].SlideURL = null;

            var result = s.Render(ses);
            Assert.IsNotNull(result, "Expected a session to be rendered");
            var v = result.Result;
            Assert.IsNotNull(v, "The visual should have shown up as well!");
            
        }

        [TestMethod]
        public void TestMetadata()
        {
            t_TestingLibrary.Utilities.AddPart(new RenderTalkAsSingleVisual());
            t_TestingLibrary.Utilities.AddPart(new RenderIndicoSession());
            t_TestingLibrary.Utilities.Compose(this);

            Session ses = new Session()
            {
                Title = "Session Title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now
            };
            ses.Talks = CreateTalks(1);

            var result = MyRender.Render(ses);
            Assert.IsNotNull(result, "Rendering session should give us something!");

            Assert.AreEqual(2, result.SGNodeList.Count, "Expected a talk image and a background image!");
        }

        [TestMethod]
        public void TestRenderTalkHSLink()
        {
            t_TestingLibrary.Utilities.AddPart(new RenderTalkAsSingleVisual());
            t_TestingLibrary.Utilities.AddPart(new RenderIndicoSession());
            t_TestingLibrary.Utilities.Compose(this);

            Session ses = new Session()
            {
                Title = "Session Title",
                ID = "5",
                StartDate = DateTime.Now,
                EndDate = DateTime.Now
            };
            ses.Talks = CreateTalks(1);

            var result = MyRender.Render(ses);

            var hsData = (from hs in result.GetHierarchicalEnumerator(ignore => false)
                          where hs.GetType() == typeof(VisualHotSpot)
                          select (VisualHotSpot)hs).ToArray();

            Assert.AreEqual(3, hsData.Length, "Expected 3 hot spot to come out of this guy");

            List<HSActionLink> links = new List<HSActionLink>();
            foreach (var item in hsData)
            {
                item.GetAllActoinData(cb =>
                {
                    var l = cb as HSActionLink;
                    if (l != null)
                        links.Add(l);
                });

            }

            Assert.AreEqual(1, links.Count, "Expected one URL link");
            Assert.AreEqual("http://www.nytimes.com", links[0].Link.OriginalString, "Unepxected URI for that link");
        }
    }
}
